/************************************************************
* @file gkt_gpio.h
************************************************************/

#ifndef GKT_GPIO_H
#define GKT_GPIO_H

#include "gkt_types.h"

#ifdef __cplusplus
extern "C" {
#endif

/************************************************************
 * GPIO hierarchy
 * 
 *  -- Device-0
 *  -- -- Port-A
 *  -- -- -- Pin-0
 *  -- -- -- ...
 *  -- -- -- Pin-m0
 *  -- -- Port-B
 *  -- -- -- Pin-0
 *  -- -- -- ...
 *  -- -- -- Pin-m1
 *  -- -- Port-C
 *  -- -- -- Pin-0
 *  -- -- -- ...
 *  -- -- -- Pin-m2
 *  -- -- Port-D
 *  -- -- -- Pin-0
 *  -- -- -- ...
 *  -- -- -- Pin-m3
 *  -- -- Port-E
 *  -- -- -- ...
 *  -- Device-N
 *  -- -- -- ...
 *
 *  Notes:
 *  1. a system could have more than one GPIO device;
 *  2. a port could be regarded as a group, a device has at least 
 *     one port and no more than four ports, each port has no more 
 *     than 32 pins;
 ************************************************************/
	/* GPIO Port/Group ID */
#define GKT_GPIO_PORTA	0
#define GKT_GPIO_PORTB	1
#define GKT_GPIO_PORTC	2
#define GKT_GPIO_PORTD	3
#define GKT_GPIO_PORTE	4
#define GKT_GPIO_PORTF	5
#define GKT_GPIO_PORT_ALL	0xff

/* Pin & dev_id, port_id, pin_id */
#define GKT_GPIO_DEVID_SHIFT	16
#define GKT_GPIO_PORTID_SHIFT	8
#define GKT_GPIO_PINID_SHIFT	0

#define GKT_GPIO_PORT(dev_id, port_id)	\
	((((uint32_t)(dev_id) & 0xff) << GKT_GPIO_DEVID_SHIFT)	\
		| (((uint32_t)(port_id) & 0xff) << GKT_GPIO_PORTID_SHIFT))

#define GKT_GPIO_PIN(dev_id, port_id, pin_id)	\
	(GKT_GPIO_PORT(dev_id, port_id)		\
		| (((uint32_t)(pin_id) & 0xff) << GKT_GPIO_PINID_SHIFT))

#define GKT_GPIO_DEVID(pin)	(((pin) >> GKT_GPIO_DEVID_SHIFT) & 0xff)
#define GKT_GPIO_PORTID(pin)	(((pin) >> GKT_GPIO_PORTID_SHIFT) & 0xff)
#define GKT_GPIO_PINID(pin)	(((pin) >> GKT_GPIO_PINID_SHIFT) & 0xff)

/* GPIO FLAGS */
#define GKT_GPIO_F_DS_MASK	0x0000FFFF

/* input & type & pull */
#define GKT_GPIO_F_INPUT	(1U << 16)
#define GKT_GPIO_F_INPUT_PULL_UP	(1U << 17)
#define GKT_GPIO_F_INPUT_PULL_DOWN	(1U << 18)
#define GKT_GPIO_F_INPUT_ANALOG	(1U << 19)

/* output & default level & mode */
#define GKT_GPIO_F_OUTPUT	(1U << 20)
#define GKT_GPIO_F_OUTPUT_HIGH	(1U << 21)
#define GKT_GPIO_F_OUTPUT_PUSH_PULL		(1U << 22)
#define GKT_GPIO_F_OUTPUT_OPEN_DRAIN	(1U << 23)

/* interrupt type & debounce */
#define GKT_GPIO_F_INT_LEVEL	(1U << 24)
#define GKT_GPIO_F_INT_EDGE		(1U << 25)
#define GKT_GPIO_F_INT_TYPE_MASK	(GKT_GPIO_F_INT_LEVEL | GKT_GPIO_F_INT_EDGE)
#define GKT_GPIO_F_INT_ACTIVE_LOW	(1U << 26)
#define GKT_GPIO_F_INT_ACTIVE_HIGH	(1U << 27)
#define GKT_GPIO_F_INT_LEVEL_LOW	(GKT_GPIO_F_INT_ACTIVE_HIGH | GKT_GPIO_F_INT_ACTIVE_LOW)
#define GKT_GPIO_F_INT_LEVEL_HIGH	(GKT_GPIO_F_INT_ACTIVE_HIGH | GKT_GPIO_F_INT_LEVEL)
#define GKT_GPIO_F_INT_EDGE_FALL	(GKT_GPIO_F_INT_ACTIVE_LOW | GKT_GPIO_F_INT_EDGE)
#define GKT_GPIO_F_INT_EDGE_RAISE	(GKT_GPIO_F_INT_ACTIVE_HIGH | GKT_GPIO_F_INT_EDGE)
#define GKT_GPIO_F_INT_DEBOUNCE	(1U << 28)
#define GKT_GPIO_F_INT_MASKED	(1U << 29)

typedef void (*gkt_gpio_irq_callback_fn)(uint32_t pin);

/*
 * GPIO INIT END HOOK
 */
#define __GPIO_INIT_END_HOOK_0	__SECTION(.rodata.hook.gie0)	/* BASE */
#define __GPIO_INIT_END_HOOK_1	__SECTION(.rodata.hook.gie1)	/* High Priority */
#define __GPIO_INIT_END_HOOK_2	__SECTION(.rodata.hook.gie2)	/* Medium Priority */
#define __GPIO_INIT_END_HOOK_3	__SECTION(.rodata.hook.gie3)	/* Low Priority */

#define GKT_GPIO_IEH_PRIORITY_BASE	0
#define GKT_GPIO_IEH_PRIORITY_HIGH	1
#define GKT_GPIO_IEH_PRIORITY_MEDIUM	2
#define GKT_GPIO_IEH_PRIORITY_LOW	3

typedef void (*gkt_gpio_init_end_hook_fn)(void);
#define GKT_GPIO_INIT_END_HOOK_DEFINE_L2(hook_fn, priority)	\
	const gkt_gpio_init_end_hook_fn __##hook_fn \
		__GPIO_INIT_END_HOOK_##priority __USED = hook_fn
#define GKT_GPIO_INIT_END_HOOK_DEFINE_L1(hook_fn, priority)	\
	GKT_GPIO_INIT_END_HOOK_DEFINE_L2(hook_fn, priority)
#define GKT_GPIO_INIT_END_HOOK_DEFINE(hook_fn, priority)	\
	GKT_GPIO_INIT_END_HOOK_DEFINE_L1(hook_fn, GKT_GPIO_IEH_PRIORITY_##priority)

typedef struct _gpio_padmux_desc {
	uint8_t	pin;	/* port_id(PORTA~E) | pin_id(0~15) */
	uint8_t	func;
} gkt_gpio_padmux_desc_s;

#define GKT_GPIO_PAD(port_id, pin_id)	\
	(((port_id) & 0x0f) << 4) | ((pin_id) & 0x0f)

#define GKT_GPIO_PADMUX_DESC_DEFINE(_pin, _func)	\
	{	\
		.pin	= _pin,	\
		.func	= _func,	\
	}

int gkt_gpio_init(void);

/************************************************************
 * @function - gkt_gpio_config
 * @brief    - configures gpio
 * @params
 *   pin          [in] gpio pin
 *   flags        [in] flags
 *   isr_callback [in] interrupt callback
 * @return value
 *   GKT_SUCCESS  - success
 *   others       - error occurs
 ************************************************************/
int gkt_gpio_config(uint32_t pin, uint32_t flags,
			gkt_gpio_irq_callback_fn irq_callback);

void gkt_gpio_unconfig(uint32_t pin);
/************************************************************
 * @function - gkt_gpio_set_pin_level
 * @brief    - set an OUTPUT pin level
 * @params
 *   pin       [in] gpio pin
 *   level     [in] output level
 * @return value
 *   GKT_SUCCESS  - success
 *   others       - error occurs
 ************************************************************/
int gkt_gpio_set_pin_level(uint32_t pin, uint32_t level);

/************************************************************
 * @function - gkt_gpio_get_pin_level
 * @brief    - get an INPUT pin level
 * @params
 *   pin       [in] gpio pin
 *   level     [out] input level
 * @return value
 *   GKT_SUCCESS  - success
 *   others       - error occurs
 * @notice
 *   if the return value is not GKT_SUCCESS, the value in out
 *   param 'level' is not meaningful
 ************************************************************/
int gkt_gpio_get_pin_level(uint32_t pin, uint32_t *level);

/************************************************************
 * @function  - gkt_gpio_set_pins_level
 * @brief     - set multiple OUTPUT pins level
 *            - the pins belongs to the same port
 * @params
 *   port_id     [in] gpio port id
 *   pins_mask   [in] pins mask
 *   level_bits  [in] level bits
 * @return value
 *   GKT_SUCCESS  - success
 *   others       - error occurs
 ************************************************************/
int gkt_gpio_set_pins_level(uint32_t port, 
				uint32_t pins_mask, uint32_t level_bits);

int gkt_gpio_get_pins_level(uint32_t port, 
				uint32_t pins_mask, uint32_t *level_bits);

/************************************************************
 * @function  - gkt_gpio_interrupt_mask/unmask/clear
 * @attention - gpio should be configured as interrupt
 ************************************************************/
void gkt_gpio_interrupt_switch_polarity(uint32_t pin);
void gkt_gpio_interrupt_mask(uint32_t pin);
void gkt_gpio_interrupt_unmask(uint32_t pin);
void gkt_gpio_interrupt_clear(uint32_t pin);

void gkt_gpio_padmux_config(const gkt_gpio_padmux_desc_s *c_desc);

#ifdef __cplusplus
}
#endif

#endif	/* GKT_GPIO_H */

